﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Web;

namespace xunsearch.lib
{
    
    /// <summary>
    /// 搜索项目主类
    /// XSFieldScheme $scheme 当前在用的字段方案
    /// string $defaultCharset 默认字符集编码
    /// string $name 项目名称
    /// XSSearch $search 搜索操作对象
    /// XSFieldMeta $idField 主键字段
    /// </summary>
    public class XS
    {
        /// <summary>
        /// XSIndex 索引操作对象
        /// </summary>
        private XSIndex _index;
        /// <summary>
        /// 最近创建的 XS 对象
        /// </summary>
        private static XS _lastXS;
        private Dictionary<string, string> _config;

        private XSServer _scws;
        private XSSearch _search;
        private XSFieldScheme _scheme, _bindScheme;
        public XS(string file) 
        {
            if (file.Length < 255 && !System.IO.File.Exists(file)) 
            {
                string file2=System.IO.Directory.GetCurrentDirectory() + "app/" + file + ".ini";
                if (System.IO.File.Exists(file2)) 
                {
                    file = file2;
                }
            }
            loadIniFile(file);
        }

        public void __destruct() 
        {
            _index = null;
            _scheme = null;
        }

        /// <summary>
        /// 获取最新的 XS 实例
        /// </summary>
        /// <returns></returns>
        public static XS getLastXS()
        {
            return _lastXS;
        }
        /// <summary>
        /// 获取当前在用的字段方案
        /// 通用于搜索结果文档和修改、添加的索引文档
        /// </summary>
        /// <returns></returns>
        public XSFieldScheme getScheme()
        {
            return _scheme;
        }


        /// <summary>
        /// 设置当前在用的字段方案
        /// </summary>
        /// <param name="fs"></param>
        public void setScheme(XSFieldScheme fs)
        {
            fs.checkValid(true);
            _scheme = fs;
            if (_search != null)
            {
                _search.markResetScheme();
            }
        }

        /// <summary>
        /// 还原字段方案为项目绑定方案
        /// </summary>
        public void restoreScheme()
        {
            if (_scheme != _bindScheme)
            {
                _scheme = _bindScheme;
                if (_search != null)
                {
                    _search.markResetScheme();
                }
            }
        }

        /// <summary>
        /// 获取配置原始数据
        /// </summary>
        /// <returns></returns>
        public Dictionary<string, string> getConfig() 
        {
            return _config;
        }

        /// <summary>
        /// 获取当前项目名称
        /// </summary>
        /// <returns></returns>
        public string getName()
        {
            return _config["project.name"];
        }

        /// <summary>
        /// 修改当前项目名称
        /// </summary>
        /// <param name="name"></param>
        public void setName(string name) 
        {
            if (_config.ContainsKey("project.name"))
            {
                _config["project.name"] = name;
            }
            else 
            {
                _config.Add("project.name", name);
            }
        }


        /// <summary>
        /// 获取项目的默认字符集
        /// </summary>
        /// <returns> 默认字符集(已大写)</returns>
        public string getDefaultCharset()
        {
            if (_config.ContainsKey("project.default_charset")) 
            {
                return _config["project.default_charset"].ToUpper();
            }
            return "UTF-8";
        }

        /// <summary>
        /// 改变项目的默认字符集
        /// </summary>
        /// <param name="charset"></param>
        public void setDefaultCharset(string charset) 
        {
            if (_config.ContainsKey("project.default_charset"))
            {
                _config["project.default_charset"] = charset.ToUpper();
            }
            else 
            {
                _config.Add("project.default_charset", charset.ToUpper());
            }
        }

        /// <summary>
        /// 获取索引操作对象
        /// </summary>
        /// <returns></returns>
        public XSIndex getIndex() 
        {
            if (_index == null) 
            {
                string[] adds=null;
                string conn = _config.ContainsKey("server.index") ? _config["server.index"] : "8383";
                int pos = conn.IndexOf(";");
                if (pos> 0) 
                {
                    adds = conn.Substring(pos + 1).Split(';');
                    conn = conn.Substring(0, pos);
                }
                _index = new XSIndex(conn, this);
                _index.setTimeout(0);
                if (adds != null) 
                {
                    foreach (string _conn in adds) 
                    {
                        string __conn = _conn.Trim();
                        if (__conn != "")
                        {
                            _index.addServer(__conn).setTimeout(0);
                        }
                    }
                }
            }

            return _index;
        }

        /// <summary>
        /// 获取搜索操作对象
        /// </summary>
        /// <returns></returns>
        public XSSearch getSearch()
        {
            if (_search == null) 
            {
                ArrayList conns = new ArrayList();
                if (!_config.ContainsKey("server.search"))
                {
                    conns.Add(8384);
                }
                else 
                {
                    foreach (string conn in _config["server.search"].Split(';')) 
                    {
                        string _conn = conn.Trim();
                        if (_conn != "") 
                        {
                            conns.Add(_conn);
                        }
                    }
                }
                if (conns.Count > 1) 
                {
                    conns.Sort();
                }
                for (int i = 0; i < conns.Count; i++) 
                {
                    try 
                    {
                        _search = new XSSearch(conns[i].ToString(), this);
                        _search.setCharset(getDefaultCharset());
                        return _search;
                    }
                    catch (Exception ex)
                    {
                        if (i + 1 == conns.Count) 
                        {
                            HttpContext.Current.Response.Write(ex.Message);
                            HttpContext.Current.Response.End();
                            throw ex;

                        }
                    }
                }
            }
            return _search;
        }
        /// <summary>
        /// 创建 scws 分词连接
        /// </summary>
        /// <returns></returns>
        public XSServer getScwsServer() 
        {
            if (_scws == null) 
            {
                string conn = _config.ContainsKey("server.search") ? _config["server.search"] : "8384";
                _scws = new XSServer(conn, this);
            }
            return _scws;
        }        

        /// <summary>
        /// 获取当前主键字段
        /// </summary>
        /// <returns></returns>
        public XSFieldMeta getFieldId() 
        {
            return _scheme.getFieldId();
        }

        /// <summary>
        /// 获取当前标题字段
        /// </summary>
        /// <returns></returns>
        public XSFieldMeta getFieldTitle() 
        {
            return _scheme.getFieldTitle();
        }
        /// <summary>
        /// 获取当前内容字段
        /// </summary>
        /// <returns>XSFieldMeta 类型为 BODY 的字段</returns>
        public XSFieldMeta getFieldBody() 
        {
            return _scheme.getFieldBody();
        }

        /// <summary>
        /// 获取项目字段元数据
        /// </summary>
        /// <param name="name"></param>
        /// <param name="is_throw"></param>
        /// <returns></returns>
        public XSFieldMeta getField(string name, bool is_throw = true)
        {
            return _scheme.getField(name, is_throw);
        }

        /// <summary>
        /// 获取项目所有字段结构设置
        /// </summary>
        /// <returns>XSFieldMeta</returns>
        public Dictionary<string,XSFieldMeta> getAllFields() 
        {
            return _scheme.getAllFields();
        }

        #region Convert

        public static string[] Convert(string[] data, string to, string from) 
        {
            if (to == from)
                return data;
            for (int i = 0; i < data.Length; i++) 
            {
                data[i] = Convert(data[i], to, from);
            }
            return data;
        }
        public static Dictionary<string, string> Convert(Dictionary<string, string> data, string to, string from) 
        {
            if (to == from) 
            {
                return data;
            }
            foreach (var de in data) 
            {
                data[de.Key] = Convert(data[de.Key], to, from);
            }
            return data;
        }

        public static List<string> Convert(List<string> data, string to, string from) 
        {
            if (to == from) 
            {
                return data;
            }
            for (int i = 0; i < data.Count; i++) 
            {
                data[i] = Convert(data[i], to, from);
            }
            return data;
        }
        /// <summary>
        /// 字符集转换
        /// </summary>
        /// <param name="data"></param>
        /// <param name="to"></param>
        /// <param name="from"></param>
        /// <returns></returns>
        public static string Convert(string data, string to, string from)
        {
            if(to==from)
            {
                return data;
            }
            byte[] temp;
            temp = Encoding.GetEncoding(to).GetBytes(data);
            temp = Encoding.Convert(Encoding.GetEncoding(to), Encoding.GetEncoding(from), temp);
            return Encoding.GetEncoding(from).GetString(temp);

        }
        #endregion
        /// <summary>
        /// 解析INI配置文件
        /// </summary>
        /// <param name="data">文件内容</param>
        /// <returns></returns>
        private Dictionary<string, string> parseIniData(string data) 
        {
            Dictionary<string, string> ret = new Dictionary<string, string>();
            string[] lines = data.Split('\n');
            int pos=0;
            string sec="";
            foreach (string line in lines) 
            {
                if (line == "" || line[0] == ';' || line[0] == '#') 
                {
                    continue;
                }
                string _line = line.Trim();
                if (_line == "") 
                {
                    continue;
                }

                if (_line[0] == '[' && _line.Substring(_line.Length - 1, 1) == "]") 
                {
                    sec = _line.Substring(1, _line.Length - 2);
                    ret.Add(sec, "");
                    continue;
                }
                if ((pos = _line.IndexOf("=")) < 0) 
                {
                    continue;
                }
                string key = _line.Substring(0, pos).Trim();
                string value = _line.Substring(pos + 1).Trim() + "";
                if (sec == "")
                {
                    if (ret.ContainsKey(key))
                    {
                        ret[key] = value;
                    }
                    else
                    {
                        ret.Add(key, value);
                    }
                }
                else
                {
                    ret[sec] = key + "\n" + value;
                    sec = "";
                }
            }
            return ret;

        }
        /// <summary>
        /// 加载项目配置文件
        /// </summary>
        /// <param name="file">配置文件路径</param>
        private void loadIniFile(string file) 
        {
            Dictionary<string,object> cache = new Dictionary<string,object>();
            string data="";
            if (file.Length < 255 && System.IO.File.Exists(file))
            {
                string cache_key = Tool.md5("::ini::" + System.IO.Directory.GetCurrentDirectory() + file);
                cache = (Dictionary<string, object>)Tool.GetCache(cache_key);
                if (cache != null)
                {
                    _scheme = _bindScheme = (XSFieldScheme)cache["scheme"];
                    _config = (Dictionary<string, string>)cache["config"];
                    return;
                }
                data = Tool.GetFile(file);
            }
            else 
            {
                data = file;
                file = Tool.md5(file).Substring(8, 8) + ".ini";
            }
            _config = parseIniData(data);
            if (_config == null) 
            {
                throw new Exception(string.Format("Failed to parse project config file/string: '{0}...'", file.Substring(0, 10)));
            }

            //create the scheme object
            XSFieldScheme scheme=new XSFieldScheme();
            foreach(var de in _config)
            {
                if(de.Value.IndexOf("\n")>0)
                {
                    scheme.addField(de.Key,Tool.GetConfigValue(de.Value));
                }
            }
            scheme.checkValid(true);
            if(!_config.ContainsKey("project.name"))
            {
                _config.Add("project.name",System.IO.Path.GetFileName(file).Replace(".ini",""));
            }

            // save to cache
            _scheme=_bindScheme=scheme;
        }
    }
}
